home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d18
/
tpdev.arc
/
TPDEV.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1991-09-27
|
5KB
|
159 lines
{ DOS character device driver written entirely in TP 6 }
{ Written by D.J. Murdoch for the public domain, May 1991 }
{$S-,F-} { Stack checking wouldn't work here, and we assume near calls
}
{$M $1000,0,0} { We can't use the heap and don't use the stack. This
setting doesn't really matter though, since you normally
won't run TPDEV }
program tpdev;
uses opint; { OPro interrupt services, needed for stack switching }
procedure strategy_routine(bp:word); interrupt; forward;
procedure interrupt_routine(bp:word); interrupt; forward;
procedure header; { Here's the trick: an assembler routine in the
main program, guaranteed to be linked first in the
.EXE file!! }
assembler;
asm
dd $FFFFFFFF { next driver }
dw $8000 { attributes of simple character device }
dw offset strategy_routine
dw offset interrupt_routine
db 'TPDEVICE'
end;
const
stDone = $100;
stBusy = $200;
cmInit = 0;
cmInput= 4;
cmInput_no_wait = 5;
cmInput_status = 6;
cmInput_flush = 7;
cmOutput = 8;
cmOutput_Verify = 9;
cmOutput_status = 10;
cmOutput_flush = 11;
type
request_header = record
request_length : byte;
subunit: byte;
command_code : byte;
status : word;
reserved: array[1..8] of byte;
case byte of
cmInit : (num_units : byte;
first_free : pointer;
args : ^char;
drive_num : byte;
);
cmInput : { also used for output }
(media_descriptor : byte;
buffer : pointer;
byte_count : word);
cmInput_no_wait : (next_char : char);
end;
var
local_stack : array[1..4000] of byte;
end_of_stack : byte;
request : ^request_header;
line : string;
procedure handler(var regs : intregisters);
{ This routine is called by the strategy routine, and handles all requests.
The data segment is okay, and we're running on the local_stack so we've got
plenty of space, but remember:
****** The initialization code for SYSTEM and all other units hasn't
ever been called!! ********
}
begin
with request^ do
begin
case command_code of
cmInit: begin
first_free := ptr(dseg,ofs(saveint75)+4); { Last thing in the
data
segment in TP6 }
{ No heap!! }
status := stDone;
line := 'TPDRIVER successfully initialized.';
end;
cmInput: begin
if byte_count > length(line) then
byte_count := length(line);
move(line[1],buffer^,byte_count);
line := copy(line,byte_count+1,255);
status := stDone;
end;
cmInput_no_wait:
begin
if length(line) > 0 then
begin
next_char := line[1];
status := stDone;
end
else
status := stBusy;
end;
cmInput_Status,cmOutput_Status,cmInput_Flush,cmOutput_Flush:
status := stDone;
cmOutput,cmOutput_Verify:
begin
if byte_count + length(line) > 255 then
byte_count := 255 - length(line);
move(buffer^,line[length(line)+1],byte_count);
line[0] := char(byte(byte_count+length(line)));
status := stDone;
end;
end;
end;
end;
procedure RetFar; assembler;
{ Replacement for the IRET code that ends the interrupt routines below }
asm
mov sp,bp
pop bp
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
retf
end;
procedure strategy_routine(bp:word);
var
regs : intregisters absolute bp;
begin
with regs do
request := ptr(es,bx);
RetFar;
end;
procedure interrupt_routine(bp:word);
var
regs : intregisters absolute bp;
begin
SwapStackandCallNear(Ofs(handler),@end_of_stack,regs);
RetFar;
end;
begin
writeln('TPDEVICE - DOS device driver written *entirely* in Turbo Pascal.');
writeln('Install using DEVICE=TPDEV.EXE in CONFIG.SYS.');
request := @header; { Need a reference to pull in the header. }
end.